import os, logging, hashlib, re, time, sys

from google.appengine.api import users
from google.appengine.ext import webapp
from google.appengine.ext import db
from google.appengine.ext.db import GqlQuery
from google.appengine.ext.webapp import template
from google.appengine.ext.webapp.util import run_wsgi_app
from google.appengine.ext.webapp.util import login_required
from google.appengine.api import memcache

import model, filters, gmemsess
from const import BASE_URL, API_KEY, SECRET_KEY, PAGE_SIZE, MAX_LOG_MESSAGES
from alerts import SendAlert

__author__="elad"
__date__ ="$Feb 19, 2009"

class LogView(webapp.RequestHandler):

	@login_required
	def get(self):		
		msg_key = self.request.get('msg')
		if (msg_key):
			self.show_message(msg_key)
		else:
			self.show_list()

	def show_message(self, msg_key):
		message = model.LogMessage.get(msg_key)
		template_values = {
			'message': message,
			}		
		path = os.path.join(os.path.dirname(__file__), 'msg.html')
		self.response.out.write(template.render(path, template_values))
	
	def show_list(self):		
		filter = filters.Filter.get_filter(self.request)
		sess = gmemsess.Session(self)
		sess['filter'] = filter
		sess.save()
		
		query = model.LogMessage.get_query_from_filter(filter)
		
		#paging
		count = query.count()
		
		pages = count / PAGE_SIZE
		
		pagep = self.request.get('page')
		if pagep is not None and len(pagep) > 0:
			page = int(pagep) - 1
		else:
			page = 0
		
		while page*PAGE_SIZE > count:
			page = page - 1
					
		if page < 0:
			page = 0
			
		offset = PAGE_SIZE*page		
		messages = query.fetch(limit=PAGE_SIZE, offset=offset)
        
		filter_str = filters.Filter.get_filter_query(filter)
        
		template_values = { 'messages': messages, 'filter': filter, 'filter_str': filter_str, 'page': page + 1, 'pages': pages + 1, 'next': page + 2, 'prev': page }
		if filter.is_saved():
			template_values['feed'] = '/feed?key=%s' % str(filter.key())
			
		path = os.path.join(os.path.dirname(__file__), 'index.html')
		self.response.out.write(template.render(path, template_values))

class LogAction(webapp.RequestHandler):

	def post(self):
		if not self.validate_signature(self.request.params):
			self.unauthorized_user()
		else:				
			message = model.LogMessage()
			message.logger_ip = self.request.remote_addr
			message.dev_mode = not (self.request.get('dev_mode') == None or self.request.get('dv') == None)
			message.app_name = self.request.get('app_name') or self.request.get('p')
			message.logger_name = self.request.get('logger_name') or self.request.get('l')
			# severity could be either a string label or an int
			severity = self.request.get('severity') or self.request.get('s')
			if re.match(r'^\d+$', severity):
				message.severity = int(severity)
			else:
				message.severity = self.severity_code(severity)			
			message.message = self.request.get('message') or self.request.get('m')
			message.stack_dump = self.request.get('stack_dump') or self.request.get('d')
			
			message_dev_mode = self.request.get('dev_mode')						
			if message_dev_mode:
				message.dev_mode = True
			else:
				message.dev_mode = False
			
			key = message.put()
			self.send_alerts(message)
			self.response.out.write("Logged %s" % key.id())

	def validate_signature(self, params):
		if (params['key'] != API_KEY):
			return False
		expected = params['sig']
		items = params.items()
		items.sort()
		s = ''
		for i in range(len(items)):
			if items[i][0] not in ('key', 'sig'):
				s += '%s%s' % (items[i][0], items[i][1])
		s += SECRET_KEY
		sig = hashlib.sha1(s).hexdigest()
		return (sig == expected)

	def unauthorized_user(self):
		self.response.set_status(403) 
		self.response.out.write("Authorization missing or incorrect")

	def severity_code(self, label):
		if (not label in model.LogMessage.Severities):
			return 0
		return model.LogMessage.Severities.index(label)

	def send_alerts(self, message):
		try:
			all_alerts = memcache.get('all_alerts')
			if all_alerts is None:
				query = model.Alert.all()
				all_alerts = query.fetch(100)			
				memcache.set('all_alerts', all_alerts)
			if all_alerts is not None:
				for alert in all_alerts:
					if alert.filter.match(message):
						result = SendAlert.send_alert(alert, message)
						if result != 200:
							logging.warn("Failed to send alert to %s; result code: %s; message: %s" % (alert.url, result.status_code, result.content))
		except:
			logging.warn("Unexpected error %s" % (sys.exc_info()[0]))
		
class ClearDB(webapp.RequestHandler):
	def get(self):
		q = db.GqlQuery("SELECT * FROM LogMessage");
		count = q.count()
		if count > MAX_LOG_MESSAGES:						
			q = db.GqlQuery("SELECT * FROM LogMessage ORDER BY timestamp");		
			results = q.fetch(250)
			db.delete(results)		
			self.response.headers['Content-Type'] = 'text/plain'
			self.response.out.write("Cleared log messages.")		
			logging.info("Cleared log messages.")
		else:
			logging.info("No need to clear messages. Message count is: %s" % count)
					
		
class FeedView(webapp.RequestHandler):

	#@login_required
	def get(self):
		filter_key = self.request.get('key')
		if (filter_key):
			filter = model.Filter.get(filter_key)
			query = model.LogMessage.get_query_from_filter(filter)
			messages = query.fetch(40)
			template_values = { 
				'messages': messages, 
				'filter': filter, 
				'now': time.strftime("%a, %d %b %Y %H:%M:%S +0000", time.localtime()),
				'base_url': BASE_URL,
			}
			path = os.path.join(os.path.dirname(__file__), 'feed.xml')
			self.response.out.write(template.render(path, template_values))
		else:
			self.response.set_status(204)


class Test(webapp.RequestHandler):

	@login_required
	def get(self):
		user = users.get_current_user()
		logger_ip = self.request.remote_addr
		template_values = {
			'user_name': user.nickname(),
			'logger_ip': logger_ip,
			}
		path = os.path.join(os.path.dirname(__file__), 'test.html')
		self.response.out.write(template.render(path, template_values))


application = webapp.WSGIApplication([('/', LogView),
									 ('/log', LogAction),
									 ('/feed', FeedView),
									 ('/cleardb', ClearDB),
                                     ('/test', Test)],
                                    debug=True)

def main():
	logging.getLogger().setLevel(logging.DEBUG)
	run_wsgi_app(application)

if __name__ == "__main__":
	main()

